package de.bk.timecalc.core;

/**
 * A simply stop watch.
 * 
 * @author Bastian Krol
 * @version $Revision:$ $Date:$ $Author:$
 */
public class StopWatch
{
  private static final long NOT_RUNNING = -1L;

  private long startMillis;

  public StopWatch()
  {
    this.startMillis = NOT_RUNNING;
  }

  /**
   * Starts the stop watch. It must not be started, otherwise an
   * IllegalStateException is thrown.
   * 
   * @throws IllegalStateException
   *           if the stop watch has been started (and not been stopped) before.
   */
  public void start()
  {
    if (this.startMillis != NOT_RUNNING)
    {
      throw new IllegalStateException(
          "StopWatch#start() has already been called. Call StopWatch#stop() needs to be called before calling StopWatch#start() again, or use StopWatch#restart().");
    }
    this.startMillis = System.currentTimeMillis();
  }

  /**
   * Stops the stop watch and returns the time. Must have been started before,
   * otherwise an IllegalStateException is thrown. May be started again
   * afterwards.
   * 
   * @return the Duration since {@link #start()} has been called
   * @throws IllegalStateException
   *           if the stop watch has not been started before (or has been
   *           started and stopped again).
   */
  public Duration stop()
  {
    if (this.startMillis == -1L)
    {
      throw new IllegalStateException(
          "StopWatch#start() has to be called before StopWatch#stop() is called.");
    }
    Duration duration = new Duration(System.currentTimeMillis()
        - this.startMillis);
    this.startMillis = -1L;
    return duration;
  }

  /**
   * Stops the stop watch, returns the time and starts the stop watch again
   * immediately. Must have been started before, otherwise an
   * IllegalStateException is thrown.
   * 
   * @return the Duration since {@link #start()} has been called
   * @throws IllegalStateException
   *           if the stop watch has not been started before (or has been
   *           started and stopped again).
   */
  public Duration restart()
  {
    Duration duration = this.stop();
    this.start();
    return duration;
  }
}
